package net.cl.utils;

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;

/**
 * 文件处理类
 * 
 * @author caol64@gmail.com
 */
public class FileUtil {

	/**
	 * 读文本文件
	 */
	public static String read(String path) throws IOException {
		File file = new File(path);
		return read(file);
	}

	/**
	 * 读文本文件
	 */
	public static String read(File file) throws IOException {
		InputStream ins = new FileInputStream(file);
		return IOUtil.toString(ins);
	}

	/**
	 * 读文本文件
	 */
	public static String read(URL url) throws IOException {
		InputStream ins = url.openStream();
		return IOUtil.toString(ins);
	}

	/**
	 * 读文本文件（指定编码）
	 */
	public static String read(String path, String charset) throws IOException {
		File file = new File(path);
		return read(file, charset);
	}

	/**
	 * 读文本文件（指定编码）
	 */
	public static String read(URL url, String charset) throws IOException {
		InputStream ins = url.openStream();
		return IOUtil.toString(ins, charset);
	}

	/**
	 * 读文本文件（指定编码）
	 */
	public static String read(File file, String charset) throws IOException {
		InputStream ins = new FileInputStream(file);
		return IOUtil.toString(ins, charset);
	}

	/**
	 * 读取二进制文件
	 */
	public static byte[] readBytes(String path) throws IOException {
		File file = new File(path);
		return readBytes(file);
	}

	/**
	 * 读取二进制文件
	 */
	public static byte[] readBytes(URL url) throws IOException {
		InputStream ins = url.openStream();
		return IOUtil.toByteArray(ins);
	}

	/**
	 * 读取二进制文件
	 */
	public static byte[] readBytes(File file) throws IOException {
		InputStream ins = new FileInputStream(file);
		return IOUtil.toByteArray(ins);
	}

	/**
	 * 以文本形式写入文件
	 */
	public static void write(String path, String content) throws IOException {
		File file = new File(path);
		write(file, content);
	}

	/**
	 * 以文本形式写入文件
	 */
	public static void write(File file, String content) throws IOException {
		if (content == null)
			content = StringUtil.NULL;
		FileWriter fw = new FileWriter(file);
		BufferedWriter bw = new BufferedWriter(fw);
		bw.write(content);
		IOUtil.closeQuietly(bw);
	}

	/**
	 * 将二进制数组写入文件
	 */
	public static void write(String path, byte[] bytes) throws IOException {
		File file = new File(path);
		write(file, bytes);
	}

	/**
	 * 将二进制数组写入文件
	 */
	public static void write(File file, byte[] bytes) throws IOException {
		if (bytes == null)
			throw new NullPointerException();
		OutputStream os = new FileOutputStream(file);
		BufferedOutputStream bos = new BufferedOutputStream(os);
		bos.write(bytes);
		IOUtil.closeQuietly(bos);
	}

	/**
	 * 将流写入文件
	 */
	public static void write(String path, InputStream ins) throws IOException {
		File file = new File(path);
		write(file, ins);
	}

	/**
	 * 将流写入文件
	 */
	public static void write(File file, InputStream ins) throws IOException {
		OutputStream os = new FileOutputStream(file);
		IOUtil.copyAndClose(ins, os);
	}

	/**
	 * 根据指定路径建一个空的文件夹
	 */
	public static File newFolder(String folderPath) {
		File file = new File(folderPath);
		return newFolder(file);
	}

	/**
	 * 根据指定路径建一个空的文件夹
	 */
	public static File newFolder(File folder) {
		if (folder == null)
			throw new NullPointerException("folder");
		folder.mkdirs();
		return folder;
	}

	/**
	 * 根据指定路径建一个文件，不会替换已存在文件
	 */
	public static File newFile(String filePath) throws IOException {
		File file = new File(filePath);
		return newFile(file, Boolean.FALSE);
	}

	/**
	 * 根据指定路径建一个文件，如果<b>rewrite</b>为<b>true</b>会替换已存在文件
	 */
	public static File newFile(String filePath, boolean rewrite) {
		return newFile(filePath, rewrite);
	}

	/**
	 * 根据指定路径建一个文件，不会替换已存在文件
	 */
	public static File newFile(File file) throws IOException {
		return newFile(file, Boolean.FALSE);
	}

	/**
	 * 根据指定路径建一个文件，如果<b>rewrite</b>为<b>true</b>会替换已存在文件
	 */
	public static File newFile(File file, boolean rewrite) throws IOException {
		if (file == null)
			throw new NullPointerException();
		if (file.isDirectory())
			return file;
		if (file.exists() && !rewrite)
			return file;
		if (file.exists() && rewrite)
			delete(file);
		newFolder(file.getParent());
		file.createNewFile();
		return file;
	}

	/**
	 * 删除一个文件或一个空的文件夹，如果文件夹不为空，则不会删除
	 */
	public static boolean delete(String path) {
		File file = new File(path);
		return delete(file, Boolean.FALSE);
	}

	/**
	 * 删除一个文件或一个空的文件夹，如果文件夹不为空，则不会删除
	 */
	public static boolean delete(File file) {
		return delete(file, Boolean.FALSE);
	}

	/**
	 * 删除一个文件或一个文件夹，如果<b>force</b>为<b>true</b>无论文件夹是否为空，都会删除
	 */
	public static boolean delete(String path, boolean force) {
		File file = new File(path);
		return delete(file, force);
	}

	/**
	 * 删除一个文件或一个文件夹，如果<b>force</b>为<b>true</b>无论文件夹是否为空，都会删除
	 */
	public static boolean delete(File file, boolean force) {
		if (file == null)
			throw new NullPointerException();
		if (file.exists()) {
			if (!force)
				return file.delete();
			else {
				if (file.isFile())
					return file.delete();
				if (file.isDirectory()) {
					File[] files = getAllFilesFromFolder(file);
					for (File f : files) {
						delete(f, force);
					}
					return file.delete();
				}
			}
		}
		return false;
	}

	/**
	 * 复制文件<b>source</b>到<b>target</b>，不会替换同名文件
	 */
	public static boolean copy(String sourcePath, String targetPath) throws IOException {
		File source = new File(sourcePath);
		File target = new File(targetPath);
		return copy(source, target, Boolean.FALSE);
	}

	/**
	 * 复制文件<b>source</b>到<b>target</b>，不会替换同名文件
	 */
	public static boolean copy(File source, File target) throws IOException {
		return copy(source, target, Boolean.FALSE);
	}

	/**
	 * 复制文件<b>source</b>到<b>target</b>，如果<b>rewrite</b>为<b>true</b>会替换同名文件
	 */
	public static boolean copy(String sourcePath, String targetPath, boolean rewrite) {
		return copy(sourcePath, targetPath, rewrite);
	}

	/**
	 * 复制文件<b>source</b>到<b>target</b>，如果<b>rewrite</b>为<b>true</b>会替换同名文件
	 */
	public static boolean copy(File source, File target, boolean rewrite) throws IOException {
		if (source == null || target == null)
			throw new NullPointerException();
		if (!source.exists())
			return Boolean.FALSE;
		if (!source.canRead())
			return Boolean.FALSE;
		if (target.exists()) {
			if (source.isDirectory() && !target.isDirectory())
				throw new IllegalArgumentException("The source file is a directory but the target is not");
			else if (!source.isDirectory() && target.isDirectory())
				throw new IllegalArgumentException("The target file is a directory but the source is not");
			if (target.isFile() && !rewrite)
				return Boolean.FALSE;
			else if (target.isFile() && rewrite)
				target.delete();
		} else {
			if (source.isDirectory())
				target.mkdirs();
			else
				newFile(target);
		}
		if (source.isDirectory()) {
			File[] files = getAllFilesFromFolder(source);
			for (File file : files) {
				copy(file, new File(target, file.getName()), rewrite);
			}
			return Boolean.FALSE;
		}
		FileInputStream fis = new FileInputStream(source);
		FileOutputStream fos = new FileOutputStream(target);
		IOUtil.copyAndClose(fis, fos);
		return Boolean.TRUE;
	}

	/**
	 * 移动文件<b>source</b>到<b>target</b>，不会替换同名文件
	 * 
	 * @throws IOException
	 */
	public static boolean move(String sourcePath, String targetPath) throws IOException {
		File source = new File(sourcePath);
		File target = new File(targetPath);
		return move(source, target, Boolean.FALSE);
	}

	/**
	 * 移动文件<b>source</b>到<b>target</b>，如果<b>rewrite</b>为<b>true</b>会替换同名文件
	 */
	public static boolean move(String sourcePath, String targetPath, boolean rewrite) throws IOException {
		File source = new File(sourcePath);
		File target = new File(targetPath);
		return move(source, target, rewrite);
	}

	/**
	 * 移动文件<b>source</b>到<b>target</b>，不会替换同名文件
	 * 
	 * @throws IOException
	 */
	public static boolean move(File source, File target) throws IOException {
		return move(source, target, Boolean.FALSE);
	}

	/**
	 * 移动文件<b>source</b>到<b>target</b>，如果<b>rewrite</b>为<b>true</b>会替换同名文件
	 * 
	 * @throws IOException
	 */
	public static boolean move(File source, File target, boolean rewrite) throws IOException {
		copy(source, target, rewrite);
		delete(source, true);
		return Boolean.TRUE;
	}

	/**
	 * 获得指定文件夹下所有文件
	 */
	public static File[] getAllFilesFromFolder(String folderPath) {
		File folder = new File(folderPath);
		return getAllFilesFromFolder(folder);
	}

	/**
	 * 获得指定文件夹下所有文件
	 */
	public static File[] getAllFilesFromFolder(File folder) {
		if (folder == null)
			throw new NullPointerException();
		return folder.listFiles();
	}

	/**
	 * 获得指定文件夹下指定后缀名的所有文件
	 */
	public static File[] getFilesFromFolder(String folderPath, final String[] extensions) {
		File folder = new File(folderPath);
		return getFilesFromFolder(folder, extensions);
	}

	/**
	 * 获得指定文件夹下指定后缀名的所有文件
	 */
	public static File[] getFilesFromFolder(File folder, final String[] extensions) {
		if (folder == null)
			throw new NullPointerException("folder");
		if (extensions == null)
			throw new NullPointerException("extensions");
		return folder.listFiles(new FilenameFilter() {
			public boolean accept(File dir, String name) {
				for (int i = 0; i < extensions.length; i++) {
					if (name.toLowerCase().endsWith(extensions[i].toLowerCase()))
						return Boolean.TRUE;
				}
				return Boolean.FALSE;
			}
		});
	}

	/**
	 * 获得指定文件夹下的符合条件的所有文件
	 */
	public static File[] getFilesFromFolder(File folder, FileFilter fileFilter) {
		if (folder == null)
			throw new NullPointerException("folder");
		if (fileFilter == null)
			throw new NullPointerException("FileFilter");
		return folder.listFiles(fileFilter);
	}

	/**
	 * 获得指定文件的后缀名
	 */
	public static String getFileExtension(File file) {
		if (file == null)
			throw new NullPointerException();
		String s = file.getName();
		int i = s.lastIndexOf('.');
		if (i > 0 && i < s.length() - 1)
			return s.substring(i + 1);
		return null;
	}

	/**
	 * 获取文件名
	 */
	public static String getFileName(String path) {
		File file = new File(path);
		return file.getName();
	}

}
